<?php


namespace app\http\middleware;

use Closure;
use think\facade\Env;
use think\facade\Log;
use think\Response;

class Signature
{
    /**
     * 接口签名验证
     * （开启了这个验证之后，会严格要求前端传过来的参数，规定每一个接口都必须有自己的一个allow参数组）
     * @param $request
     * @param Closure $next
     * @return mixed
     */
    public function handle($request, Closure $next):Response
    {
        //接口路径
        $path = $request->baseUrl();
        $timestamp = $request->header('Timestamp');//请求时间戳
        $signature = $request->header('Signature');//前端提交的签名
        //参数过滤，对于配置文件中的字段定义，前端加密的时候可以少传，但不能多传
        $only = config("signature.{$request->controller()}.{$request->action()}");
        /**
         * 这里可以取param、post、get，严格程度依次递减
         * param：对所有参数都会要求签名验证
         * post：仅对post参数会要求签名验证
         * get：仅对get参数会要求签名验证
         */
        $param = $request->param($only);
        $paramStr = $param ? json_encode($param) : '';
        //按顺序加密
        if(md5($path.$paramStr.$timestamp.Env::get('secret.signature')) != $signature) {
            Log::record('path: '.$path);
            Log::record('paramsStr: '.$paramStr);
            Log::record('timestamp: '.$timestamp);
            Log::record('key: '.Env::get('secret.signature'));
            Log::record('request signature: '.$signature);
            //如果签名验证不正确，直接响应签名错误标识403
            return json('Signature Invalid')->code(403);
        }

        return $next($request);
    }
}